// Ignore the following symbols
%ignore WorkReg; 
%ignore AbstractRegister;
%ignore rginfo;
%ignore insn_t::get_canon_mnem;
%ignore insn_t::get_canon_feature;
%ignore insn_t::is_canon_insn;
%ignore bytes_t;
%ignore IDPOPT_STR;
%ignore IDPOPT_NUM;
%ignore IDPOPT_BIT;
%ignore IDPOPT_FLT;
%ignore IDPOPT_I64;
%ignore IDPOPT_OK;
%ignore IDPOPT_BADKEY;
%ignore IDPOPT_BADTYPE;
%ignore IDPOPT_BADVALUE;
%ignore set_options_t;
%ignore read_user_config_file;

%ignore s_preline;
%ignore ca_operation_t;
%ignore _chkarg_cmd;
%ignore ENUM_SIZE;

%ignore asm_t::checkarg_dispatch;
%ignore asm_t::func_header;
%ignore asm_t::func_footer;
%ignore asm_t::get_type_name;
%ignore instruc_t;
%ignore processor_t;
%ignore ph;
%ignore IDB_Callback;

%ignore free_processor_module;
%ignore read_config_file;

%ignore gen_idb_event;

%include "idp.hpp"

%feature("director") IDB_Hooks;

%inline %{
int idaapi IDB_Callback(void *ud, int notification_code, va_list va);
class IDB_Hooks 
{
public:
    virtual ~IDB_Hooks() {};

    bool hook() { return hook_to_notification_point(HT_IDB, IDB_Callback, this); }
    bool unhook() { return unhook_from_notification_point(HT_IDB, IDB_Callback, this); }
    /* Hook functions to override in Python */
    virtual int byte_patched(ea_t ea) { return 0; };
    virtual int cmt_changed(ea_t, bool repeatable_cmt) { return 0; };
    virtual int ti_changed(ea_t ea, const type_t *type, const p_list *fnames) { msg("ti_changed hook not supported yet\n"); return 0; };
    virtual int op_ti_changed(ea_t ea, int n, const type_t *type, const p_list *fnames) { msg("op_ti_changed hook not supported yet\n"); return 0; };
    virtual int op_type_changed(ea_t ea, int n) { return 0; };
    virtual int enum_created(enum_t id) { return 0; };
    virtual int enum_deleted(enum_t id) { return 0; };
    virtual int enum_bf_changed(enum_t id) { return 0; };
    virtual int enum_renamed(enum_t id) { return 0; };
    virtual int enum_cmt_changed(enum_t id) { return 0; };
    virtual int enum_const_created(enum_t id, const_t cid) { return 0; };
    virtual int enum_const_deleted(enum_t id, const_t cid) { return 0; };
    virtual int struc_created(tid_t struc_id) { return 0; };
    virtual int struc_deleted(tid_t struc_id) { return 0; };
    virtual int struc_renamed(struc_t *sptr) { return 0; };
    virtual int struc_expanded(struc_t *sptr) { return 0; };
    virtual int struc_cmt_changed(tid_t struc_id) { return 0; };
    virtual int struc_member_created(struc_t *sptr, member_t *mptr) { return 0; };
    virtual int struc_member_deleted(struc_t *sptr, tid_t member_id) { return 0; };
    virtual int struc_member_renamed(struc_t *sptr, member_t *mptr) { return 0; };
    virtual int struc_member_changed(struc_t *sptr, member_t *mptr) { return 0; };
    virtual int thunk_func_created(func_t *pfn) { return 0; };
    virtual int func_tail_appended(func_t *pfn, func_t *tail) { return 0; };
    virtual int func_tail_removed(func_t *pfn, ea_t tail_ea) { return 0; };
    virtual int tail_owner_changed(func_t *tail, ea_t owner_func) { return 0; };
    virtual int func_noret_changed(func_t *pfn) { return 0; };
    virtual int segm_added(segment_t *s) { return 0; };
    virtual int segm_deleted(ea_t startEA) { return 0; };
    virtual int segm_start_changed(segment_t *s) { return 0; };
    virtual int segm_end_changed(segment_t *s) { return 0; };
    virtual int segm_moved(ea_t from, ea_t to, asize_t size) { return 0; };
};

int idaapi IDB_Callback(void *ud, int notification_code, va_list va)
{
  class IDB_Hooks *proxy = (class IDB_Hooks *)ud;
  ea_t ea, ea2;
  bool repeatable_cmt;
  /*type_t *type;*/
  /*  p_list *fnames; */
  int n;
  enum_t id;
  const_t cid;
  tid_t struc_id;
  struc_t *sptr;
  member_t *mptr;
  tid_t member_id;
  func_t *pfn;
  func_t *tail;
  segment_t *seg;
  asize_t size;

  try {
    switch (notification_code)
    {
    case idb_event::byte_patched:
      ea = va_arg(va, ea_t);
      return proxy->byte_patched(ea);

    case idb_event::cmt_changed:
      ea = va_arg(va, ea_t);
      repeatable_cmt = va_arg(va, int);
      return proxy->cmt_changed(ea, repeatable_cmt);
#if 0
    case idb_event::ti_changed:
      ea = va_arg(va, ea_t);
      type = va_arg(va, type_t *);
      fnames = va_arg(va, fnames);
      return proxy->ti_changed(ea, type, fnames);

    case idb_event::op_ti_changed:
      ea = va_arg(va, ea_t);
      n = va_arg(va, int);
      type = va_arg(va, type_t *);
      fnames = va_arg(va, fnames);
      return proxy->op_ti_changed(ea, n, type, fnames);
#endif
    case idb_event::op_type_changed:
      ea = va_arg(va, ea_t);
      n = va_arg(va, int);
      return proxy->op_type_changed(ea, n);

    case idb_event::enum_created:
      id = va_arg(va, enum_t);
      return proxy->enum_created(id);

    case idb_event::enum_deleted:
      id = va_arg(va, enum_t);
      return proxy->enum_deleted(id);

    case idb_event::enum_bf_changed:
      id = va_arg(va, enum_t);
      return proxy->enum_bf_changed(id);

    case idb_event::enum_cmt_changed:
      id = va_arg(va, enum_t);
      return proxy->enum_cmt_changed(id);

    case idb_event::enum_const_created:
      id = va_arg(va, enum_t);
      cid = va_arg(va, const_t);
      return proxy->enum_const_created(id, cid);

    case idb_event::enum_const_deleted:
      id = va_arg(va, enum_t);
      cid = va_arg(va, const_t);
      return proxy->enum_const_deleted(id, cid);

    case idb_event::struc_created:
      struc_id = va_arg(va, tid_t);
      return proxy->struc_created(struc_id);

    case idb_event::struc_deleted:
      struc_id = va_arg(va, tid_t);
      return proxy->struc_deleted(struc_id);

    case idb_event::struc_renamed:
      sptr = va_arg(va, struc_t *);
      return proxy->struc_renamed(sptr);

    case idb_event::struc_expanded:
      sptr = va_arg(va, struc_t *);
      return proxy->struc_expanded(sptr);

    case idb_event::struc_cmt_changed:
      struc_id = va_arg(va, tid_t);
      return proxy->struc_cmt_changed(struc_id);

    case idb_event::struc_member_created:
      sptr = va_arg(va, struc_t *);
      mptr = va_arg(va, member_t *);
      return proxy->struc_member_created(sptr, mptr);

    case idb_event::struc_member_deleted:
      sptr = va_arg(va, struc_t *);
      member_id = va_arg(va, tid_t);
      return proxy->struc_member_deleted(sptr, member_id);

    case idb_event::struc_member_renamed:
      sptr = va_arg(va, struc_t *);
      mptr = va_arg(va, member_t *);
      return proxy->struc_member_renamed(sptr, mptr);

    case idb_event::struc_member_changed:
      sptr = va_arg(va, struc_t *);
      mptr = va_arg(va, member_t *);
      return proxy->struc_member_changed(sptr, mptr);

    case idb_event::thunk_func_created:
      pfn = va_arg(va, func_t *);
      return proxy->thunk_func_created(pfn);

    case idb_event::func_tail_appended:
      pfn = va_arg(va, func_t *);
      tail = va_arg(va, func_t *);
      return proxy->func_tail_appended(pfn, tail);

    case idb_event::func_tail_removed:
      pfn = va_arg(va, func_t *);
      ea = va_arg(va, ea_t);
      return proxy->func_tail_removed(pfn, ea);

    case idb_event::tail_owner_changed:
      tail = va_arg(va, func_t *);
      ea = va_arg(va, ea_t);
      return proxy->tail_owner_changed(tail, ea);

    case idb_event::func_noret_changed:
      pfn = va_arg(va, func_t *);
      return proxy->func_noret_changed(pfn);

    case idb_event::segm_added:
      seg = va_arg(va, segment_t *);
      return proxy->segm_added(seg);

    case idb_event::segm_deleted:
      ea = va_arg(va, ea_t);
      return proxy->segm_deleted(ea);

    case idb_event::segm_start_changed:
      seg = va_arg(va, segment_t *);
      return proxy->segm_start_changed(seg);

    case idb_event::segm_end_changed:
      seg = va_arg(va, segment_t *);
      return proxy->segm_end_changed(seg);

    case idb_event::segm_moved:
      ea = va_arg(va, ea_t);
      ea2 = va_arg(va, ea_t);
      size = va_arg(va, asize_t);
      return proxy->segm_moved(ea, ea2, size);
    }
  }
  catch (Swig::DirectorException &) 
  { 
    msg("Exception in IDP Hook function:\n"); 
    if (PyErr_Occurred())
    {
      PyErr_Print();
    }
  }
  return 0;
}

// Assemble an instruction into the database (display a warning if an error is found)
// args:
//  ea_t ea -  linear address of instruction
//  ea_t cs -  cs of instruction
//  ea_t ip -  ip of instruction
//  bool use32 - is 32bit segment?
//  const char *line - line to assemble
// returns: 1: success, 0: failure 
inline const int assemble(ea_t ea, ea_t cs, ea_t ip, bool use32, const char *line)
{
    int inslen;
    char buf[MAXSTR];

    if (ph.notify != NULL)
    {
        inslen =  ph.notify(ph.assemble, ea, cs, ip, use32, line, buf);
        if (inslen > 0)
	{
            patch_many_bytes(ea, buf, inslen);
            return 1;
	}
    }
    return 0;
}

//<inline(py_idp)>
//-------------------------------------------------------------------------

//-------------------------------------------------------------------------
// Assemble an instruction to a buffer (display a warning if an error is found)
// args:
//  ea_t ea -  linear address of instruction
//  ea_t cs -  cs of instruction
//  ea_t ip -  ip of instruction
//  bool use32 - is 32bit segment?
//  const char *line - line to assemble
// returns: 1: success, 0: failure 
static PyObject *AssembleLine(ea_t ea, ea_t cs, ea_t ip, bool use32, const char *line)
{
  int inslen;
  char buf[MAXSTR];
  if (ph.notify != NULL &&
    (inslen =  ph.notify(ph.assemble, ea, cs, ip, use32, line, buf)) > 0)
  {
    return PyString_FromStringAndSize(buf, inslen);
  }
  Py_RETURN_NONE;
}

//-------------------------------------------------------------------------
static size_t ph_get_tbyte_size()
{
  return ph.tbyte_size;
}

//-------------------------------------------------------------------------
static PyObject *ph_get_instruc()
{
  Py_ssize_t i = 0;
  PyObject *py_result = PyTuple_New(ph.instruc_end - ph.instruc_start);
  for ( instruc_t *p = ph.instruc + ph.instruc_start, *end = ph.instruc + ph.instruc_end;
        p != end;
        ++p )
  {
    PyTuple_SetItem(py_result, i++, Py_BuildValue("(sI)", p->name, p->feature));
  }
  return py_result;
}

//-------------------------------------------------------------------------
static PyObject *ph_get_regnames()
{
  Py_ssize_t i = 0;
  PyObject *py_result = PyList_New(ph.regsNum);
  for ( Py_ssize_t i=0; i<ph.regsNum; i++ )
    PyList_SetItem(py_result, i, PyString_FromString(ph.regNames[i]));
  return py_result;
}

//</inline(py_idp)>
%}
